import http from '@ohos.net.http';
import request from '@ohos.request';
import installer from '@ohos.bundle.installer';
import fs from '@ohos.file.fs';
import { promptAction } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
import { bundleManager } from '@kit.AbilityKit';
import { GlobalContext } from './GlobalContext';

const releaseUrl = 'https://gitee.com/api/v5/repos/ericple/applications_settings_6t/releases';

interface IAuthorInfo {
  id: number;
  login: string;
  name: string;
  avatar_url: string;
  url: string;
  html_url: string;
  remark: string;
  followers_url: string;
  following_url: string;
  gists_url: string;
  starred_url: string;
  subscriptions_url: string;
  organizations_url: string;
  repos_url: string;
  events_url: string;
  received_events_url: string;
  type: string;
}

interface IAssetInfo {
  browser_download_url: string;
  name: string;
}

export interface IReleaseInfo {
  id: number;
  tag_name: string;
  target_commitish: string;
  prerelease: boolean;
  name: string;
  body: string;
  author: IAuthorInfo;
  created_at: string;
  assets: IAssetInfo[];
}

class CUpdateUtil {
  private _lastCheckTime: number = 0;
  private _cachedReleaseInfo?: IReleaseInfo = undefined;
  private _cachedUpdateAvail?: boolean = undefined;
  private _downloadTask: request.DownloadTask;
  private progress: number = 0;

  checkUpdate() {
    return new Promise<boolean>(resolve => {
      if (this.isCacheValid() && this._cachedUpdateAvail != undefined) {
        resolve(this._cachedUpdateAvail);
      } else {
        this._lastCheckTime = Date.now();
        const client = http.createHttp();
        client.request(releaseUrl)
          .then(result => {
            const releaseInfo: Array<IReleaseInfo> = JSON.parse(result.result.toString());
            const currentVer = bundleManager.getBundleInfoForSelfSync(0).versionName;
            if (releaseInfo.length != 0 && releaseInfo[releaseInfo.length-1].tag_name != currentVer) {
              this._cachedReleaseInfo = releaseInfo[releaseInfo.length-1];
              resolve(true);
            } else {
              resolve(false);
            }
          })
          .catch((reason) => {
            console.log('UpdateUtil catch:', JSON.stringify(reason));
            resolve(false);
          })
      }
    })
  }

  startUpdate(info: IReleaseInfo, context: any) {
    return new Promise<void>((resolve, reject) => {
      const fp = context.filesDir + '/updatePack.hap';
      if (fs.accessSync(fp)) {
        fs.unlinkSync(fp);
      }
      const filteredArr = info.assets.filter(v => v.browser_download_url.endsWith('.hap'));
      if (filteredArr.length == 0) {
        reject('该发行版本无可用安装包');
        return;
      }
      const downloadUrl = filteredArr[0].browser_download_url;
      console.log('Update download url:', downloadUrl, 'save as:', fp);
      request.downloadFile(context, {
        url: downloadUrl,
        background: true,
        title: '设置正在更新',
        filePath: fp
      }).then(task => {
        this._downloadTask = task;
        this._downloadTask.on('progress', (received, total) => {
          this.progress = 100 * received / total;
          AppStorage.setOrCreate('updateProgress', this.progress.toFixed(1));
        });
        this._downloadTask.on('complete', () => {
          promptAction.showToast({ message: '设置即将更新，将会退出' });
          installer.getBundleInstaller().then(bi => {
            bi.install([fp], {
              isKeepData: true,
              installFlag: 0x01
            }).catch((err: BusinessError) => {
              console.log('installer error during update:', JSON.stringify(err));
            })
          })
        })
        resolve();
      }).catch(reason => {
        reject(reason);
      });
    })
  }

  getUpdateProgress() {
    if (this._downloadTask == undefined) {
      return -1;
    }
    return this.progress;
  }

  getLatest() {
    // 如果小于查询间隔，返回缓存更新信息
    return new Promise<IReleaseInfo>((resolve, reject) => {
      if (this.isCacheValid() && this._cachedReleaseInfo != undefined) {
        resolve(this._cachedReleaseInfo)
      } else {
        const client = http.createHttp();
        client.request(releaseUrl)
          .then(result => {
            const releaseInfo: Array<IReleaseInfo> = JSON.parse(result.result.toString());
            if (releaseInfo.length == 0) {
              reject('更新列表为空');
            } else {
              resolve(releaseInfo[releaseInfo.length-1]);
            }
          })
          .catch((reason) => {
            console.log('UpdateUtil catch:', JSON.stringify(reason));
            reject('获取更新信息时发生异常，请查看应用日志')
          })
      }
    })
  }

  getCurrentVersion() {
    return bundleManager.getBundleInfoForSelfSync(0).versionName;
  }

  private isCacheValid() {
    return Date.now() - this._lastCheckTime < 5 * 60 * 1000;
  }
}

export const UpdateUtil = new CUpdateUtil;